#define LOG_TAG "whatJNI"

#include <jni.h>                                                                                                                                                                                             

#include <opencv2/opencv.hpp>
#include <opencv2/legacy/legacy.hpp>

#include <iostream>     
#include <fstream>
#include <string>
#include <utility>
#include <vector>
#include <map>

#include "decode_yuv420sp_nv21.h"
#include "face_detect.h"

//for dir_operations()
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <stddef.h>


using namespace cv; 
using namespace std;

#include "tools.h"

static CvHaarClassifierCascade * faceCascade = NULL;
const static char *CASCADE_FACE = "/sdcard/haarcascade_frontalface_alt2.xml";

extern "C" {                                                                                                                                                                                                 

    /*  
     * Load face cascadeclassifer file
     * 
     *@return: true if success, else false
     */
    JNIEXPORT jboolean JNICALL
        Java_com_example_getcamerapreviewtest_CameraPreview_nativeInit( JNIEnv* env, jobject obj);

    /*  
     * @param recog: 
     *              true to do recognize; false not to recog
     * @return: 
     */
    JNIEXPORT jintArray JNICALL
        Java_com_example_getcamerapreviewtest_CameraPreview_nativeDetect( JNIEnv* env, jobject obj, jbyteArray buf, int w, int h);

}

jboolean 
Java_com_example_getcamerapreviewtest_CameraPreview_nativeInit( JNIEnv* env, jobject obj) {

    if (faceCascade == NULL) {
        MY_LOG("Load cascade file: %s", CASCADE_FACE);
        faceCascade = (CvHaarClassifierCascade*)cvLoad(CASCADE_FACE, 0, 0, 0 );
        if ( NULL == faceCascade ) {
            return JNI_FALSE;
        }
    }
    return JNI_TRUE;
}

static int gOldW = 0, gOldH = 0;
static IplImage *gIplOrig = NULL;
static char *gCbgra = NULL;

jintArray Java_com_example_getcamerapreviewtest_CameraPreview_nativeDetect( JNIEnv* env, jobject obj, jbyteArray buf, int w, int h) {
    MY_LOG("w:%d, h:%d", w, h);
    jbyte* cbuf = env->GetByteArrayElements(buf, 0);
    int *arrRects = NULL;

    if(gIplOrig == NULL || gCbgra == NULL || gOldW != h || gOldH != h) {//first or changed

        if (NULL == gIplOrig) {cvReleaseImageHeader(&gIplOrig);}
        if (NULL == gCbgra) {free(gCbgra);}

        gIplOrig = cvCreateImageHeader(cvSize(w, h), IPL_DEPTH_8U, 4);
        gCbgra = (char *) malloc (gIplOrig->widthStep * h * 4);
        cvSetData(gIplOrig, gCbgra, gIplOrig -> widthStep);
    }

    decodeYuv420sp_bgr0(gCbgra, (char *)cbuf, w, h);

    std::vector<CvRect> vectRects;
    face_detect(gIplOrig, &vectRects, faceCascade, true /*detect_only*/);

    const int len_results = 1 + vectRects.size()*4;
    arrRects = (int *)malloc(len_results);
    arrRects[0] = vectRects.size();
    for(int i = 0; i < vectRects.size(); i ++) {
        int j = 0;
        arrRects[1 + i*4 + (j++ % 4)] = vectRects[i].x;
        arrRects[1 + i*4 + (j++ % 4)] = vectRects[i].y;
        arrRects[1 + i*4 + (j++ % 4)] = vectRects[i].width;
        arrRects[1 + i*4 + (j++ % 4)] = vectRects[i].height;
    }
    
    for(int i = 0; i < len_results; i ++) {
        //MY_LOG("arrRects[%d] = %d", i, arrRects[i]);
    }

    jintArray result = env->NewIntArray(len_results);                                                                                                                                                               
    env->SetIntArrayRegion(result, 0, len_results, arrRects);
    env->ReleaseByteArrayElements(buf, cbuf, 0);
    free(arrRects);

    gOldW = w; 
    gOldH = h;
    return result;
}


JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {

    MY_LOG("JNI_OnLoad startup~~!");
    return JNI_VERSION_1_6;

}
